﻿using System.Security.Cryptography;
using System.Text;


namespace Sage.Encryption
{

    /// <summary>
    /// 提供基于AES-GCM算法的加密服务实现(更安全的选择)
    /// </summary>
    public class AesGcmEncryptionService : IEncryptionService, IDisposable
    {
        private readonly byte[] _key;
        private readonly int _nonceSize;
        private readonly int _tagSize;
        private bool _disposed;

        /// <summary>
        /// 使用指定的密钥创建AES-GCM加密服务实例
        /// </summary>
        public AesGcmEncryptionService(byte[] key, int nonceSize = 12, int tagSize = 16)
        {
            ArgumentNullException.ThrowIfNull(key);

            if (key.Length is not (16 or 24 or 32))
                throw new ArgumentException("密钥长度必须为16、24或32字节", nameof(key));

            _key = (byte[])key.Clone();
            _nonceSize = nonceSize;
            _tagSize = tagSize;
        }

        /// <summary>
        /// 使用密码和盐值创建AES-GCM加密服务实例
        /// </summary>
        public AesGcmEncryptionService(string password, string salt, int iterations = 10000)
        {
            ArgumentException.ThrowIfNullOrEmpty(password);
            ArgumentException.ThrowIfNullOrEmpty(salt);

            if (iterations < 1)
                throw new ArgumentException("迭代次数必须大于0", nameof(iterations));

            byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
            _key = new byte[32];

            // 使用 Span 重载，直接写入目标数组
            Rfc2898DeriveBytes.Pbkdf2(
                password,
                saltBytes,
                _key.AsSpan(),
                iterations,
                HashAlgorithmName.SHA256
            );

            _nonceSize = 12;
            _tagSize = 16;
        }

        /// <inheritdoc/>
        public byte[] Encrypt(string plainText)
        {
            ArgumentException.ThrowIfNullOrEmpty(plainText);
            return Encrypt(Encoding.UTF8.GetBytes(plainText));
        }

        /// <inheritdoc/>
        public byte[] Encrypt(byte[] plainBytes)
        {
            ArgumentNullException.ThrowIfNull(plainBytes);
            ObjectDisposedException.ThrowIf(_disposed, this);

            // 生成随机nonce
            var nonce = new byte[_nonceSize];
            RandomNumberGenerator.Fill(nonce);

            // 准备输出数组: nonce + tag + ciphertext
            var cipherBytes = new byte[_nonceSize + _tagSize + plainBytes.Length];

            // 复制nonce到输出数组
            nonce.CopyTo(cipherBytes, 0);

            // 加密 - 修复过时的构造函数使用
            using var aesGcm = new AesGcm(_key, _tagSize);
            var tag = new byte[_tagSize];

            aesGcm.Encrypt(
                nonce,
                plainBytes,
                cipherBytes.AsSpan(_nonceSize + _tagSize), // 密文写入位置
                tag);

            // 复制tag到输出数组
            tag.CopyTo(cipherBytes.AsSpan(_nonceSize));

            return cipherBytes;
        }

        /// <inheritdoc/>
        public Task<byte[]> EncryptAsync(byte[] plainBytes)
        {
            // AesGcm是同步API，为保持接口一致提供异步包装
            return Task.FromResult(Encrypt(plainBytes));
        }

        /// <inheritdoc/>
        public string DecryptToString(byte[] cipherBytes)
        {
            return Encoding.UTF8.GetString(Decrypt(cipherBytes));
        }

        /// <inheritdoc/>
        public byte[] Decrypt(byte[] cipherBytes)
        {
            ArgumentNullException.ThrowIfNull(cipherBytes);
            ObjectDisposedException.ThrowIf(_disposed, this);

            if (cipherBytes.Length < _nonceSize + _tagSize)
                throw new ArgumentException("密文数据格式不正确");

            // 提取nonce, tag和密文
            var nonce = cipherBytes.AsSpan(0, _nonceSize);
            var tag = cipherBytes.AsSpan(_nonceSize, _tagSize);

            // 计算密文长度
            int ciphertextLength = cipherBytes.Length - _nonceSize - _tagSize;
            var plaintext = new byte[ciphertextLength];

            // 解密 - 修复过时的构造函数使用
            using var aesGcm = new AesGcm(_key, _tagSize);
            aesGcm.Decrypt(
                nonce,
                cipherBytes.AsSpan(_nonceSize + _tagSize, ciphertextLength),
                tag,
                plaintext);

            return plaintext;
        }

        /// <inheritdoc/>
        public Task<byte[]> DecryptAsync(byte[] cipherBytes)
        {
            // AesGcm是同步API，为保持接口一致提供异步包装
            return Task.FromResult(Decrypt(cipherBytes));
        }

        /// <summary>
        /// 释放资源并安全清除敏感数据
        /// </summary>
        public void Dispose()
        {
            if (!_disposed)
            {
                Array.Clear(_key);
                _disposed = true;
                GC.SuppressFinalize(this);
            }
        }
    }


}
